package com.happy.config;

import com.happy.util.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * @Author: Wuzh
 * @Description: 日志切面，通过该切面进行日志捕获和处理
 * @Date Created in 22:56 2020/8/17
 * @return
 */
@Component
@Aspect
@Slf4j
public class LogAspect {

    /**
     * @Author: Wuzh
     * @Description: 作用到具体方法上，哪个方法上用了LogPoint注解，就会被切
     * @Data:
     */
    //@Pointcut ("execution(public * com.praise.*.*Controller.*(..))")
    @Pointcut ("@annotation(com.happy.config.LogPointer)")
    public void pointcut () {
    }

    @Around ("pointcut()")
    public Object around ( ProceedingJoinPoint point ) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes ();
        HttpServletRequest request = attributes.getRequest ();
        String operatorName = getOperatorName ( point ); // 加在切面的注解值
        String url = request.getRequestURL ().toString ();
        String reqParam = preHandle ( point, request );//JsonUtil.beanToJsonString(point.getArgs()[0]);
        //获取方法
        Method method = ( (MethodSignature) point.getSignature () ).getMethod ();
        log.info ( "{}-请求参数:[{}],请求URL:[{}]", operatorName, reqParam, url );
        long begin = System.currentTimeMillis ();
        Object result = point.proceed (); //反射执行具体方法
        String respParam = postHandle ( result );
        log.info ( "{}-请求IP:[{}], 耗时：[{}ms],返回参数:[{}]", operatorName, url, ( System.currentTimeMillis () - begin ), /*resultBody*/respParam );
        return result;
    }


    /**
     * @Author: Wuzh
     * @Description: 获取自定义注解value值
     * @Data:
     */
    private String getOperatorName ( ProceedingJoinPoint joinPoint ) {
        Signature signature = joinPoint.getSignature ();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method targetMethod = methodSignature.getMethod ();
        LogPointer operateName = targetMethod.getAnnotation ( LogPointer.class );
        return operateName.value ();
    }


    /**
     * 入参数据
     *
     * @param joinPoint
     * @param request
     * @return
     */
    private String preHandle ( ProceedingJoinPoint joinPoint, HttpServletRequest request ) {
        String reqParam = "";
        Signature signature = joinPoint.getSignature ();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method targetMethod = methodSignature.getMethod ();
        Annotation[] annotations = targetMethod.getAnnotations ();
        for ( Annotation annotation : annotations ) {
            if ( annotation.annotationType ().equals ( RequestMapping.class ) || annotation.annotationType ().equals ( GetMapping.class ) || annotation.annotationType ().equals ( PostMapping.class ) || annotation.annotationType ().equals ( PutMapping.class ) || annotation.annotationType ().equals ( DeleteMapping.class ) ) {
                reqParam = JsonUtil.beanToJsonString ( joinPoint.getArgs () );
                break;
            }
        }
        return reqParam;
    }


    private String postHandle ( Object retVal ) throws IOException {
        if ( null == retVal ) {
            return "";
        }
        return JsonUtil.beanToJsonString ( retVal );
    }
}
